Introduzione all'assembly
Gennaio 2000 - Cosma Colanicchia
cloud.cc@tiscalinet.it
Ottimizzato per la risoluzione di 1024x768 pixel


il computer
  il processore
  la memoria
  gli interrupt
 

Il computer ha come scopo quello di eseguire dei programmi, cioè delle sequenze di istruzioni. Un programma per essere eseguito deve innanzitutto essere caricato in memoria, dopodichè il processore si occupa di svolgere, una dopo l'altra, tutte le istruzioni che lo compongono. Abbiamo visto quindi due delle componenti fondamentali del PC: Il processore e la memoria.

Il processore è l'unita centrale di elaborazione (CPU) del computer ed è costutuito da un'unità aritmetico-logica (ALU), un'unità di governo e da una memoria locale formata da diversi registri.
L'unità aritmetico logica è un dispositico capace di eseguire le operazioni aritmetiche, logiche e di confronto su dati prelevati dalla memoria. In poche parole è una calcolatrice a cui di volta in volta vengono forniti l'operatore e gli operandi, e che produce un risultato.
L'unità di governo invece ha il compito di interpretare l'istruzione da eseguire e comandare di conseguenza l'ALU.
Entrambi questi componenti colloquiano con la memoria locale, che abbiamo detto essere formata da dispositivi di memorizzazione detti registri.

i registri generici sono quattro, ognuno è progettato per eseguire in particolare una determinata funzione, ma possono essere usati (quasi) a piacimento.
AX registro accumulatore
BX registro base
CX registro contatore
DX registro dati

Come tutti gli altri registri della CPU, i registri generici sono a 16 bit (cioè ognuno è composto da 2 byte di memoria). Durante la scrittura di un programma assembly possiamo fare riferimento anche esclusivamente al byte alto o a quello basso di ognuno di questi registri:

Un'altra importante serie di registri sono i registri segmento. Essi sono utilizzati dal processore per localizzare una determinata cella di memoria: contengono infatti l'indirizzo della prima cella del relativo segmento (i segmenti e l'indirizzamento della memoria verranno tratato tra poche righe). I registri segmento sono:
CS code segment
DS data segment
ES extra segment
SS stack segment

Infine, i registri puntatori sono in qualche modo complementari a quelli segmento: mentre questi ultimi vengono usati per individuare i segmenti da 64Kb all'interno della memoria, i 5 registri puntatori servono per individuare, attraverso di uno l'indirizzo di spiazzamento (in inglese offset), una locazione all'interno di uno specifico segmento. Questi 5 registri sono:
 
 

IP (istruction pointer) fornisce l'offset della cella di memoria (all'interno del segmento individuato da CS) che contiene la prossima istruzione da eseguire
SP (stack pointer) punta alla testa dello stack nel segmento individuato da SS
BP (base pointer) puntatore utilizzato per le operazione nello stack nel segmento individuato da SS
SI (source index) puntatore usato per lo spiazzamento negli indirizzamenti all'interno del segmento dati individuato da DS
DI (destination index) puntantore usato per lo spiazzamento negli indirizzamenti all'interno del segmento dati individuato da DS o nel segmento extra individuato da ES

la memoria è la capacita di conservare informazioni. All'interno del computer il dispositivo che si occupa di questo è la RAM (Random Access Memory), in cui vengono posti i programmi in esecuzione con i relativi dati. La RAM del computer è divisa in celle da un bye ciascuna,e ad ogni cella è associato un indirizzo, che può andare da 0 fino al numero di celle presenti. Anche tale numero è conservato in forma binaria, e la sua lunghezza è di 20 bit. Con 20 bit possiamo contare fino a 220 = 1 milione di celle circa (1Mbyte infatti è la massima memoria indirizzabile dall'i8086), per chiarimenti consultare l'appendice sistemi di numerazione.
Durante la scrittura di un programma però si presenta un problema: come facciamo ad esprimere un indirizzo a 20 bit usando solo registri a 16 bit? Per farlo si divide la memoria in segmenti di 64Kbyte ciascuno (con 16 bit possiamo contare infatti fino a 64K celle), e si indirizza una cella attraverso due registri: in uno viene posto l'indirizzo di partenza del segmento, e nell'altro l'offset, cioè la distanza della cella da esso. I due registri coinvolti nel caso la cella contenga un'istruzione sono la coppia CS:IP, nel caso di dati su usa in genere la coppia di registri DS:SI o DS:DI.
Nel primo registro è indicato il segmento (non a caso il registro usato si chiama registro segmento), nel secondo l'offset.
 

In figura, per indirizzare la cella B che contiene codice da eseguire, si utilizzano CS:IP, dove CS contiene l'indirizzo di partenza del segmento (la cella A) e IP la distanza di B da esso (l'indirizzo di B meno l'indirizzo di A) cioè l'offset.

Durante l'esecuzione di un programma, il registro Code Segment (CS) indica sempre il segmento di memoria dove è contenuto il codice da eseguire, il Data Segment (DS) quello dove sono contenuti i dati e così via.
I registri della CPU e la RAM si scambiano continuamente dati, attraverso un BUS dati a 16 bit (cioè in grado di trasferire 2 byte di informazioni in un unico passaggio), mentre lo scambio degli indirizzo avviene attravarso un BUS dedicato (bus indirizzi) a 20 bit.
 

gli interrupt sono uno strumento usato dalla CPU per interfacciarsi alle altre componenti del computer. Spesso una periferica ha bisogno di richiamare l'attenzione della CPU al verificarsi di un evento. Ad esempio, la tastiera deve rendere noto al sistema che un tasto è stato premuto. Per farlo utilizza un interrupt, o interruzione. In pratica, forza la CPU ad abbandonare temporaneamente quello che stava facendo e ad occuparsi della gestione dell'evento che si è verificato.
Il processore, quando arriva una rischiesta di interrupt (un flag viene portato a 1) deve innanzitutto riconoscere quale periferica lo ha richiesto. Ogni periferica ha il suo indirizzo (livello di interrupt), e lo comunica alla CPU attraverso un bus apposito ogni volta che richiede un interrupt. La CPU riconosce tale indirizzo, sospende l'operazione in corso (in pratica salva lo stato di tutti i registri in una memoria apposita) e localizza l'handler di tale interruzione. Una volta eseguito, ripristina lo stato originario e prosegue in ciò che stava elaborando prima della chiamata. L'handler di un interrupt è uno spezzone di codice, caricato in memoria all'avvio del computer, che serve a gestire quell'evento. Nelle prime celle di memoria è presente una tabella, in cui ad ogni livello di interrupt è associato l'indirizzo del relativo handler.
Il sistema è in grado di eseguire un solo interrupt alla volta. Se durante l'esecuzione di un handler viene segnalato un'altro interrupt, la chiamata viene ignorata.
 

Una periferica, quando deve segnalare un evento alla CPU tramite un interrupt, pone il suo identificativo nel BUS dedicato, e mette a 1 IF (interrupt flag). La CPU riconosce la periferica leggendo l'identificativo sul BUS, localizza nella tabella degli interrupt l'handler giusto e, dopo aver salvato il suo stato, lo esegue. Durante questo passaggio eventuali altre chiamate di interrupt verranno ignorate. Infine ripristina il suo stato originario e riprende il processo che aveva sospeso.
Gli handler sono piccoli programmi che fanno parte del sistema operativo. Tuttavia, possiamo anche definirne di nostri. Basta scrivere il codice relativo, metterlo in memoria come TSR (Terminate and Stay Resident: una volta eseguito, non viene scaricato dalla memoria) e porre il suo indirizzo nella tabella degli interrupt.
Esistono due tipi di chiamate di interrupt: sincrone ed asincrone. Le chiamate asincrone sono quelle che vengono generate dalle periferiche in modo imprevedibile (possono arrivare in qualsiasi momento), mentre quelle sincrone sono quelle che il programmatore genera con un'apposita istruzione assembly (l'istruzione INT).


torna alla homepage / torna all'inizio / prossima sezione